
package com.gopay.bis.citic.fund.operation;

import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 这里采用RSA算法进行密匙动作,MD5作为摘要算法,并在此基础上进行签名与验签
 * @RSA.java
 * @author dong-wang5@hnari.com
 * @2016年7月20日 上午10:02:40  www.gopay.com.cn Inc.All rights reserved.
 */
public class RSA 
{
   public static final int    DEFAULT_KEY_SIZE    = 1024;
   public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
   public static final String KEY_GEN_ALGORITHM   = "RSA";
    
   /**
     * @param keySize
     * @param seed
     * @return KeyPairԿ��
     */
    public static KeyPair generateKeyPair(int keySize, byte[] seed) 
    {
        if (keySize != DEFAULT_KEY_SIZE) 
        {
            keySize = DEFAULT_KEY_SIZE;
        }
        KeyPair keys = null;    
        try 
        {
            KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_GEN_ALGORITHM);
            SecureRandom secureRandom = new SecureRandom();
            secureRandom.setSeed(seed);
            keygen.initialize(keySize, secureRandom);
            keys = keygen.genKeyPair();
        } 
        catch (NoSuchAlgorithmException e) 
        {
            throw new RuntimeException("", e);
        }
        return keys;
    }
    /**
     * 
     * @param privateKey
     * @param source
     * @return
     */
    public static byte[] sign(byte[] privateKey, byte[] source) 
    {
        byte[] signed = null;
        try 
        {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(privateKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_GEN_ALGORITHM);
            PrivateKey priKey = keyFactory.generatePrivate(priPKCS8);
            Signature signer = Signature.getInstance(SIGNATURE_ALGORITHM);
            signer.initSign(priKey);
            signer.update(source);
            signed = signer.sign();
        } 
        catch (NoSuchAlgorithmException e) 
        {
            throw new RuntimeException("*NoSuchAlgorithmException*", e);
        } 
        catch (InvalidKeySpecException e) 
        {
            throw new RuntimeException("*InvalidKeySpecException*", e);
        } 
        catch (InvalidKeyException e) 
        {
            throw new RuntimeException("*InvalidKeyException*", e);
        } 
        catch (SignatureException e) 
        {
            throw new RuntimeException("*SignatureException*", e);
        }
        return signed;
    }

    /**
     * 
     * @param publicKey
     * @param source
     * @param signed
     * @return
     */
    public static boolean verify(byte[] publicKey, byte[] source, byte[] signed) 
    {
        try 
        {
            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(publicKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_GEN_ALGORITHM);
            PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);

            Signature checker = Signature.getInstance(SIGNATURE_ALGORITHM);
            checker.initVerify(pubKey);
            checker.update(source);
          if (checker.verify(signed)) 
          {
                return true;
          }
        } 
        catch (NoSuchAlgorithmException e) 
        {
            throw new RuntimeException("NoSuchAlgorithmException->", e);
        } 
        catch (InvalidKeySpecException e) 
        {
            throw new RuntimeException("InvalidKeySpecException->", e);
        } 
        catch (InvalidKeyException e) 
        {
            throw new RuntimeException("InvalidKeySpecException->", e);
        } 
        catch (SignatureException e) 
        {
            throw new RuntimeException("InvalidKeySpecException->", e);
        }
        return false;
    }
}
